﻿@page "/pages/authentication/loginwith2fa"
@using CleanArchitecture.Blazor.Domain.Identity
@using System.ComponentModel.DataAnnotations

@inject IStringLocalizer<LoginWith2fa> L
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@inject IdentityRedirectManager RedirectManager
@inject ILogger<LoginWith2fa> Logger

<PageTitle>@L["Two-factor authentication"]</PageTitle>
<MudText Typo="Typo.h4" GutterBottom="true">@L["Two-factor authentication"]</MudText>

<MudText Typo="Typo.body1">@L["Your login is secured with two-factor authentication via email. Please enter the code sent to your email address below."]</MudText>

<div class="d-flex flex-column gap-y-3">
    <div class="d-flex flex-column">
        <EditForm Model="Input" FormName="login-with-2fa" OnValidSubmit="OnValidSubmitAsync" method="post">
            <input type="hidden" name="ReturnUrl" value="@ReturnUrl"/>
            <input type="hidden" name="RememberMe" value="@RememberMe"/>
            <DataAnnotationsValidator/>
            <StatusMessage Message="@message" Error="true"/>
            <div class="mud-input-control mud-input-outlined-with-label my-4">
                <div class="mud-input-control-input-container">
                    <!--!--><!--!-->
                    <div class="mud-input mud-input-outlined mud-input-outlined-with-label mud-shrink mud-typography-subtitle1">
                        <InputText @bind-Value="Input.TwoFactorCode" class="mud-input-slot mud-input-root mud-input-root-outlined" type="text" autocomplete="off" aria-required="true"/>
                        <div class="mud-input-slot mud-input-root mud-input-root-outlined" style="display:none"></div>
                        <!--!-->
                        <fieldset class="mud-input-outlined-border"><legend>@L["Authenticator code"]</legend></fieldset>
                    </div>
                    <!--!-->
                    <label class="mud-input-label mud-input-label-animated mud-input-label-outlined mud-input-label-inputcontrol" for="twoFactorCode">@L["Authenticator code"]</label>
                </div>
                <div class="mud-input-helper-text mud-input-error">
                    <div class="d-flex">
                        <ValidationMessage For="() => Input.TwoFactorCode" class="mud-input-error"/>
                    </div>
                </div>
            </div>

            <div class="checkbox mb-3">
                <label for="remember-machine" class="form-label">
                    <InputCheckbox @bind-Value="Input.RememberMachine"/>
                    Remember this machine
                </label>
            </div>
            <div>
                <MudButton Variant="Variant.Filled"
                           Color="Color.Primary"
                           Size="Size.Large"
                           ButtonType="ButtonType.Submit"
                           FullWidth="true">
                    <MudText>@L["Sign In"]</MudText>
                </MudButton>
            </div>
        </EditForm>
    </div>

    @* 
    <MudText Typo="Typo.body1">
        @L["Don't have access to your authenticator device? You can"]
    </MudText>
    <a class="mud-button-root mud-button mud-button-text mud-button-text-default mud-button-text-size-medium mud-ripple" href="@($"{LoginWithRecoveryCode.PageUrl}?ReturnUrl={ReturnUrl}")">log in with a recovery code</a>. 
    *@
</div>

@code {
    public const string PageUrl = "/pages/authentication/loginwith2fa";
    private string? message;
    private ApplicationUser user = default!;

    [SupplyParameterFromForm] private InputModel Input { get; set; } = new();

    [SupplyParameterFromQuery] private string? ReturnUrl { get; set; }

    [SupplyParameterFromQuery] private bool RememberMe { get; set; }


    protected override async Task OnInitializedAsync()
    {
        // Ensure the user has gone through the username & password screen first
        user = await SignInManager.GetTwoFactorAuthenticationUserAsync() ??
               throw new InvalidOperationException(L["Unable to load two-factor authentication user."]);
    }

    private async Task OnValidSubmitAsync()
    {
        var authenticatorCode = Input.TwoFactorCode!.Replace(" ", string.Empty).Replace("-", string.Empty);
        var isCodeValid = await UserManager.VerifyTwoFactorTokenAsync(user, SignInManager.Options.Tokens.AuthenticatorTokenProvider, authenticatorCode);
        if (!isCodeValid)
        {
            message = L["Error: Invalid authenticator code."];
            return;
        }

        var result = await SignInManager.TwoFactorSignInAsync(SignInManager.Options.Tokens.AuthenticatorTokenProvider, authenticatorCode, RememberMe, RememberMe);
        var userId = await UserManager.GetUserIdAsync(user);
        if (result.Succeeded)
        {
            Logger.LogInformation("User with ID '{UserId}' logged in with 2fa.", userId);
            RedirectManager.RedirectTo(ReturnUrl);
        }
        else if (result.IsLockedOut)
        {
            Logger.LogWarning("User with ID '{UserId}' account locked out.", userId);
            RedirectManager.RedirectTo(Lockout.PageUrl);
        }
        else
        {
            Logger.LogWarning("Invalid authenticator code entered for user with ID '{UserId}'.", userId);
            message = L["Error: Invalid authenticator code."];
        }
    }

    private sealed class InputModel
    {
        [Required]
        [StringLength(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Text)]
        [Display(Name = "Authenticator code")]
        public string? TwoFactorCode { get; set; }

        [Display(Name = "Remember this machine")]
        public bool RememberMachine { get; set; }
    }

}